<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>函数代码查找变量(Function code searches for variables)</title>
  <!-- 
  在JavaScript中，函数代码中的变量查找是一个重要的概念，涉及到作用域、变量提升和闭包等机制。
  一、作用域（Scope）
  1. 局部作用域：
    - 在函数内部声明的变量只能在该函数内部访问，这种变量称为局部变量。
    function myFunction() {
      var localVar = "我是局部变量";
      console.log(localVar); // 可以访问局部变量
    }

    myFunction();
    console.log(localVar); // 报错: localVar is not defined
  2. 全局作用域：
    - 在函数外部声明的变量可以在整个脚本中访问，这种变量称为全局变量。
    var globalVar = "我是全局变量";

    function anotherFunction() {
      console.log(globalVar); // 可以访问全局变量
    }

    anotherFunction(); // 输出: 我是全局变量

  二、变量查找的顺序
  当在函数内部访问变量时，JavaScript会按照以下顺序查找：
  1. 当前作用域：首先在当前函数的局部作用域中查找。
  2. 外部作用域：如果在当前作用域中找不到，会向外层作用域查找，直到找到变量或达到全局作用域。
  3. 全局作用域：如果仍然找不到变量，则会查找全局作用域。
  var outerVar = "我是外部变量";
  function outerFunction() {
    var innerVar = "我是内部变量";

    function innerFunction() {
      console.log(innerVar); // 访问内部变量
      console.log(outerVar); // 访问外部变量
    }
    innerFunction();
  }

  outerFunction();
  三、变量提升（Hoisting）

  在JavaScript中，函数内的变量声明会被提升到函数的顶部，但赋值不会提升。这意味着你可以在声明之前访问变量，但其值为 `undefined` 。
  function hoistingExample() {
    console.log(hoistedVar); // 输出: undefined
    var hoistedVar = "我是提升的变量";
    console.log(hoistedVar); // 输出: 我是提升的变量
  }

  hoistingExample();

  四、闭包（Closure）
  闭包是指一个函数可以访问其外部作用域的变量，即使外部函数已经返回。闭包允许函数“记住”外部变量的状态。
  function makeCounter() {
    let count = 0; // 局部变量

    return function() {
      count += 1; // 访问外部变量
      return count;
    };
  }

  const counter = makeCounter();
  console.log(counter()); // 输出: 1
  console.log(counter()); // 输出: 2

  五、总结
  - 在函数代码中，变量的查找遵循作用域链的规则，优先在当前作用域查找，然后是外部作用域，最后是全局作用域。
  - 变量提升允许在声明之前访问变量，但值为 `undefined` 。
  - 闭包使得内部函数能够访问外部函数的变量，从而实现数据的封装和持久化。
    -->
</head>
<body>

  <script>
    // 作用域链
    // 域：如果仍然找不到变量，则会查找全局作用域。
    var outerVar = "我是外部变量";
    function outerFunction() {
      var innerVar = "我是内部变量";

      function innerFunction() {
        console.log(innerVar); // 访问内部变量
        console.log(outerVar); // 访问外部变量
      }
      innerFunction();
    }

    outerFunction();

    // 变量提升
    // 声明提升：变量声明会被提升到作用域的顶部，但赋值不会提升。
    function hoistingExample() {
      console.log(hoistedVar); // 输出: undefined
      var hoistedVar = "我是提升的变量";
      console.log(hoistedVar); // 输出: 我是提升的变量
    }

    hoistingExample();

    // 闭包
    // 闭包是指一个函数可以访问其外部作用域的变量，即使外部函数已经返回。
    function makeCounter() {
      let count = 0; // 局部变量

      return function() {
        count += 1; // 访问外部变量
        return count;
      };
    }

    // 对象函数优先级
    var message = "Global message";
    
    function foo() {
      console.log(message);
    }

    foo()

    var obj = {
      message: "Object message",
      bar: function() {
        var message = "bar message";
        foo();
      },
      baz: function() {
        var message = "baz message";
          function foo() {
          console.log(message);
        }
        foo()
      }
    }

    obj.bar(); // 输出: Global message
    obj.baz(); // 输出: baz message
    
  </script>
  
</body>
</html>